#include <stdlib.h>
#include <stdio.h>
#include "ff.h"
#include "tga_image.h"
struct tga_header_t{
    uint8_t  id_length;         // size of ID field that follows 18 uint8_t header (0 usually)
    uint8_t  c_map_type;        // type of colour map should be 2 = uncompressed RGB
    uint8_t  image_type;        // type of image 0=none,1=indexed,2=rgb,3=grey,+8=rle packed
    uint16_t c_map_start;       // first colour map entry in palette
    uint16_t c_map_length;      // number of colours in palette
    uint8_t  c_map_depth;       // number of bits per palette entry 15,16,24,32
    uint16_t x_start;           // image x origin
    uint16_t y_start;           // image y origin
    uint16_t image_width;       // image width in pixels
    uint16_t image_height;      // image height in pixels
    uint8_t  image_depth;       // image bits per pixel 8,16,24,32
    uint8_t  descriptor;        // image descriptor bits (vh flip bits)
}__attribute__((packed));

struct tga_image_t{
    FIL fp;                         //tga file handle
    struct tga_header_t tga_header; //tga header
};

int tga_image_alloc(struct tga_image_t **tga_image)
{
    int ret = 0;
    *tga_image = malloc(sizeof(struct tga_image_t));
    if (tga_image == NULL) {
        ret = -1;
    }
    return ret;
}

void tga_image_free(struct tga_image_t *tga_image)
{
    f_close(&tga_image->fp);
    free(tga_image);
}

int tga_image_open(struct tga_image_t *tga_image, const char *path)
{
    UINT bytes;
    struct tga_header_t *tga_header;
    
    tga_header = &tga_image->tga_header;

    if (f_open(&tga_image->fp, path, FA_READ|FA_OPEN_EXISTING) != 0) { //open image file
        printf("f_open() failed %s\n", path);
        goto error;
    }
    
    bytes = sizeof(struct tga_header_t);
    if (f_read(&tga_image->fp, tga_header, bytes, &bytes) !=  FR_OK || //read tga header
            bytes != sizeof(struct tga_header_t)) {
        printf("f_read()");
        goto error;
    }
 
    if (tga_header->image_type != 0x02) { //only uncompressed RGB is supported
        printf("unsupported image type %d\n", tga_header->image_type);
        goto error;
    }
 
    if (tga_header->image_depth != 0x18) { //only 24-bit RGB is supported
        printf("unsupported color depth %d\n", tga_header->image_depth);
        goto error;
    }

    //skip id_length bytes before reading data
    if (tga_header->id_length) {
        //f_seek(?
    }

    return 0;
error:
    return -1;
}

int tga_image_read(struct tga_image_t *tga_image, uint8_t *buf)
{
    uint8_t ibuf[3072];  //1024 pixels
    register uint8_t *ibuf_ptr, *obuf_ptr = buf;
    UINT bytes;
    register uint32_t i, x, size;

    //image size in pixels
    size = tga_image->tga_header.image_width * tga_image->tga_header.image_height;

    //copy image to frame buffer
    for (i= 0; i< size; i+= sizeof(ibuf) / 3) {
        bytes = sizeof(ibuf);
        if (f_read(&tga_image->fp, ibuf, bytes, &bytes) != FR_OK) {
            printf("unexpected EOF\n");
            goto error;
        }
        //mask out bits for RGB565
        for (x= 0, ibuf_ptr= ibuf; x< bytes; x+= 3, ibuf_ptr+= 3, obuf_ptr+= 2) {
            obuf_ptr[0] = (*ibuf_ptr & 0xf8) | (ibuf_ptr[1] >> 5);
            obuf_ptr[1] = ((ibuf_ptr[1] & 0x1c)<<3) | (ibuf_ptr[2] >> 3);            
        }
    }
    return 0;
error:
    return -1;
}

int tga_image_width(struct tga_image_t *tga_image)
{
    return tga_image->tga_header.image_width;
}

int tga_image_height(struct tga_image_t *tga_image)
{
    return tga_image->tga_header.image_height;
}

int tga_image_depth(struct tga_image_t *tga_image)
{
    return tga_image->tga_header.image_depth;
}
